
#include <algorithm>
#include <iostream>
#include <memory>
#include <string.h>

#include "range_file.h"

/******************************************

int MyFClose(FILE *stream)
{
    std::cout << "MyFClose(FILE *)" << std::endl;
    return fclose(stream);
}

int main()
{
    // using ScopedFILE = std::unique_ptr<FILE, decltype(&fclose)>;
    using ScopedFILE = std::unique_ptr<FILE, decltype(&MyFClose)>;
    ScopedFILE filePtr(fopen("./data.txt", "w+"), MyFClose);
    char buf[] = "hello smartptr!";
    fwrite(buf, sizeof(char), strlen(buf), filePtr.get());

    return 0;
}


//
// (转) C语言: fopen() 函数 打开模式 mode 整理 "https://www.cnblogs.com/yongdaimi/p/17376133.html"
//

函数说明：移动stream文件指针，从origin地址开始，移动offset个偏移字节。那么，origin参数有如下的取值：

SEEK_SET： 文件开头
SEEK_CUR： 当前位置
SEEK_END： 文件结尾

其中SEEK_SET,SEEK_CUR和SEEK_END依次为0，1和2数值。可以举例如下：
fseek(fp,100L,0);把fp指针移动到离文件开头100字节处；
fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处；
fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。
参数offset为偏移量，正数表示正向偏移，负数表示负向偏移。
返回值：成功返回0，失败返回-1。

******************************************/

struct stat get_fileinfo(const char *filename)
{
    struct stat file_stat;
    if (lstat(filename, &file_stat) == -1)
    {
        perror("lstat");
    }
    return file_stat;
}

size_t uploadfile(const char *filename, size_t rangeStartPos, const char *buf, size_t buflen)
{
    if (rangeStartPos > 0 && access(filename, F_OK) != 0)
    {
        perror("file not exist, cannot append write!");
        return -1;
    }

    FILE *pfile = nullptr;

    if (rangeStartPos > 0)
    {
        struct stat file_stat;
        lstat(filename, &file_stat);
        size_t file_sz = file_stat.st_size;
        if (rangeStartPos > file_sz)
        {
            perror("rangeStartPos bigger than file_sz, please check rangeStartPos!");
            return -1;
        }

        pfile = fopen(filename, "r+"); // 打开文件进行“读写”操作，即既可读取，又可写入。若欲操作的文件不存在，则打开失败。
    }
    else
    {
        pfile = fopen(filename, "w+"); // "w+" rangeStartPos=0 时候, 文件不存在创建文件,
    }

    fseek(pfile, rangeStartPos, SEEK_SET);
    fwrite(buf, sizeof(char), buflen, pfile);
    fclose(pfile);

    return rangeStartPos + buflen;
}

size_t downloadfile(const char *src_filename, const char *dst_filename, size_t rangeStartPos, size_t uploadlen)
{
    if (access(src_filename, F_OK) != 0)
    {
        perror("src_filename not exist!");
        return -1;
    }

    if (rangeStartPos > 0 && access(dst_filename, F_OK) != 0)
    {
        perror("dst_filename not exist, cannot append write!");
        return -1;
    }

    FILE *psrc_file = nullptr;
    FILE *pdst_file = nullptr;

    if (rangeStartPos > 0)
    {
        struct stat src_file_stat;
        lstat(src_filename, &src_file_stat);
        size_t src_file_sz = src_file_stat.st_size;

        struct stat dst_file_stat;
        lstat(dst_filename, &dst_file_stat);
        size_t dst_file_sz = dst_file_stat.st_size;

        if (rangeStartPos > src_file_sz || rangeStartPos > dst_file_sz)
        {
            perror("rangeStartPos bigger than src_file_sz and bigger than dst_file_sz!");
            return -1;
        }

        psrc_file = fopen(src_filename, "r");
        pdst_file = fopen(dst_filename, "r+"); // 打开文件进行“读写”操作，即既可读取，又可写入。若欲操作的文件不存在，则打开失败。
    }
    else
    {
        psrc_file = fopen(src_filename, "r");
        pdst_file = fopen(dst_filename, "w+");
    }

    fseek(psrc_file, rangeStartPos, SEEK_SET);
    fseek(pdst_file, rangeStartPos, SEEK_SET);

    const size_t BUF_LEN = 1024;
    char buf[BUF_LEN] = {};
    size_t total_readlen = 0;

    if (uploadlen > BUF_LEN)
    {
        // uploadlen 过大, 每次读取 BUF_LEN 进行写入,
        size_t readlen = 0;
        size_t read_size = std::min(uploadlen - total_readlen, BUF_LEN);
        while ((readlen = fread(buf, sizeof(char), read_size, psrc_file)) > 0)
        {
            total_readlen += readlen;
            if (feof(psrc_file))
            {
                printf("已经到达文件末尾\n");
            }
            fwrite(buf, sizeof(char), readlen, pdst_file);
        }
    }
    else
    {
        total_readlen = fread(buf, sizeof(char), uploadlen, psrc_file);
        if (feof(psrc_file))
        {
            printf("已经到达文件末尾\n");
        }
        fwrite(buf, sizeof(char), total_readlen, pdst_file);
    }
    fclose(psrc_file);
    fclose(pdst_file);

    return total_readlen + rangeStartPos;
}